/*
 * Funny Language - a free style programming language.
 * Copyright (C) 2015 by fanguangping (fanguangping@163.com)
 * init.c
 */

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <limits.h>
#include "common.h"

#define MAX_SIZE       512

#define COMMENT_CHAR   '$'
#define STATEMENT_CHAR 's'
#define STATEMENT_STR  "statement:"
#define NAME_CHAR      'n'
#define NAME_STR       "name:"
#define FUNCTION_CHAR  'f'
#define FUNCTION_STR   "function:"
#define MAPPING_CHAR   'm'
#define MAPPING_STR    "mapping:"
#define RUN_CHAR       'r'
#define RUN_STR        "run:"
#define EVAL_CHAR      'e'
#define EVAL_STR       "eval:"

static String load_init_file(String filepath) {
	Statement *s = NULL;
	FILE *fp = NULL;

	fp = fopen( filepath, "rb");
	if (!fp)
		perror(filepath), exit(1);

	while (has_next_statement(fp)) {
		s = next_statement(fp);
		match(s);
	}

	fclose(fp);
	return NULL;
}

int funny_init(Funny *funny, Scheme *sc) {
	funny->sc = sc;

	char currentPath[PATH_MAX];
	if (getcwd(currentPath, sizeof(currentPath)) == NULL) {
		perror("getcwd() error");
		return FALSE;
	}
	funny->cwd = currentPath;

	char *funnyHome = getenv(FUNNY_HOME);
	if (funnyHome == NULL) {
		fprintf(stderr, "You should set the environment variable 'FUNNY_HOME' first!");
		exit(0);
	}
	char *sysMacroFile = dyna_strcat(copy_string(funnyHome), SYS_MACRO_FILE);
	char *sysInitFile = dyna_strcat(copy_string(funnyHome), SYS_INIT_FILE);

	parse_sys_macro(sysMacroFile);
	load_init_file(sysInitFile);
	functions = init_queue();

	chdir(funny->cwd);

	return TRUE;
}

void add_mapping_to_trie(Mapping *mapping) {
	trie_add(mappingTrie, mapping);
}

Queue *get_mappings(Statement *s) {
	if (s == NULL)
		return NULL;
	return trie_find(mappingTrie, s);
}

Queue *get_functions() {
	if (functions == NULL) {
		functions = init_queue();
	}
	return functions;
}

static String get_sys_macro_string(String s, FILE *fp) {
	int c = 0;
	int i = 0;
	String macro = NULL;

	i = strlen(s);
	while (i > 0) {
		c = getc(fp);
		i--;
	}

	i = 0;
	macro = alloc_string(MAX_SIZE);
	while (c != '\n') {
		c = getc(fp);
		macro[i++] = c;
	}
	macro[--i] = '\0';

	return trim_string(macro);
}

void parse_sys_macro(String fileName) {
	String source = NULL;
	mappingTrie = init_trie(calc_mapping_prefix, calc_statement_prefix);
	Mapping *mapping = NULL;

	FILE *fp = NULL;
	int c = 0;

	fp = fopen( fileName, "rb");
	if (!fp)
		perror(fileName), exit(1);

	while (TRUE) {
		c = getc(fp);

		if (c == -1)
			break;

		if (c == COMMENT_CHAR) {
			while (c != '\n')
				c = getc(fp);
			continue;
		}

		if (c == STATEMENT_CHAR) {
			source = get_sys_macro_string(STATEMENT_STR, fp);

			mapping = alloc_mapping();
			mapping->sys = alloc_sys_block();
			mapping->isMacro = FALSE;
			mapping->className = NULL;
			mapping->functionName = NULL;
			mapping->source = source;
			mapping->sourceStatement = parse(source);
			mapping->target = NULL;
			mapping->targetStatement = NULL;
			mapping->starter = to_dfa(mapping->sourceStatement);

			continue;
		} else if (c == NAME_CHAR) {
			mapping->sys->name = get_sys_macro_string(NAME_STR, fp);
			continue;
		} else if (c == FUNCTION_CHAR) {
			mapping->sys->function = get_sys_macro_string(FUNCTION_STR, fp);
			continue;
		} else if (c == MAPPING_CHAR) {
			mapping->sys->mapping = get_sys_macro_string(MAPPING_STR, fp);
			continue;
		} else if (c == RUN_CHAR) {
			mapping->sys->run = get_sys_macro_string(RUN_STR, fp);
			continue;
		} else if (c == EVAL_CHAR) {
			mapping->sys->eval = get_sys_macro_string(EVAL_STR, fp);
			trie_add(mappingTrie, mapping);
			continue;
		} else {
			while (c != '\n')
				c = getc(fp);
			continue;
		}
	}

	fclose(fp);
}
